package com.bungarus.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by tang on 2018/12/16.
 */
@Configuration
@PropertySource("application.properties")
public class BusiSpringConfig {
    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.database}")
    private int database;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.password}")
    private String password;

    @Value("${spring.redis.cluster.nodes}")
    private String cluster_nodes;

    @Value("${spring.redis.cluster.max-redirects}")
    private int maxRedirects;

    @Value("${spring.redis.ssl}")
    private boolean ssl;

    @Value("${spring.redis.timeout}")
    private int timeout;

    @Value("${spring.redis.read-timeout}")
    private int readTimeout;

    @Value("${spring.redis.sentinel.master}")
    private String master;

    @Value("${spring.redis.sentinel.nodes}")
    private String sentinel_nodes;

    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;

    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;

    @Value("${spring.redis.jedis.pool.max-wait}")
    private int maxWait;

    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;

    @Value("${bungarus.gs.redis.host}")
    private String gsHost;

    @Value("${bungarus.gs.redis.port}")
    private int gsPort;

    @Value("${bungarus.gs.redis.password}")
    private String gsPassword;


    //    @Bean("clusterConnectionFactory")
    public JedisConnectionFactory jedisClusterConnectionFactory() {
        if(StringUtils.isEmpty(cluster_nodes)){
            return null;
        }
        Map<String, Object> clusterConfigs = new HashMap<>();
        clusterConfigs.put("spring.redis.cluster.nodes", cluster_nodes);
        clusterConfigs.put("spring.redis.cluster.max-redirects", maxRedirects);
        RedisClusterConfiguration redisClusterConfiguration
                = new RedisClusterConfiguration(new MapPropertySource("redisClusterConfig", clusterConfigs));
        if(!StringUtils.isEmpty(password)) {
            redisClusterConfiguration.setPassword(password);
        }

        return new JedisConnectionFactory(redisClusterConfiguration, clientConfigurationBuilder().build());
    }

//    @Bean("sentinelConnectionFactory")
    public JedisConnectionFactory jedisSentinelConnectionFactory() {
        if(StringUtils.isEmpty(sentinel_nodes)){
            return null;
        }
        Map<String, Object> sentinelConfigs = new HashMap<>();
        sentinelConfigs.put("spring.redis.sentinel.nodes", sentinel_nodes);
        sentinelConfigs.put("spring.redis.sentinel.master", master);

        RedisSentinelConfiguration redisSentinelConfiguration =
                new RedisSentinelConfiguration(new MapPropertySource("redisSentinelConfig", sentinelConfigs));
        redisSentinelConfiguration.setDatabase(database);
        if(!StringUtils.isEmpty(password)) {
            redisSentinelConfiguration.setPassword(password);
        }

        return new JedisConnectionFactory(redisSentinelConfiguration, clientConfigurationBuilder().build());
    }

    //    @Bean("gsSentinelConnectionFactory")
    public JedisConnectionFactory jedisGSSentinelConnectionFactory() {
        if(StringUtils.isEmpty(sentinel_nodes)){
            return null;
        }
        Map<String, Object> sentinelConfigs = new HashMap<>();
        sentinelConfigs.put("bungarus.gs.redis.sentinel.nodes", sentinel_nodes);
        sentinelConfigs.put("bungarus.gs.redis.sentinel.master", master);

        RedisSentinelConfiguration redisSentinelConfiguration =
                new RedisSentinelConfiguration(new MapPropertySource("redisSentinelConfig", sentinelConfigs));
        redisSentinelConfiguration.setDatabase(database);
        if(!StringUtils.isEmpty(password)) {
            redisSentinelConfiguration.setPassword(password);
        }

        return new JedisConnectionFactory(redisSentinelConfiguration, clientConfigurationBuilder().build());
    }

    @Bean("standaloneConnectionFactory")
    public JedisConnectionFactory jedisStandaloneConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration =
                new RedisStandaloneConfiguration(host, port);
        if(!StringUtils.isEmpty(password)) {
            redisStandaloneConfiguration.setPassword(password);
        }
        return new JedisConnectionFactory(redisStandaloneConfiguration, clientConfigurationBuilder().build());
    }

    @Bean("jedisDSStandaloneConnectionFactory")
    public JedisConnectionFactory groupServiceJedisStandaloneConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration =
                new RedisStandaloneConfiguration(gsHost, gsPort);
        if(!StringUtils.isEmpty(gsPassword)) {
            redisStandaloneConfiguration.setPassword(gsPassword);
        }
        return new JedisConnectionFactory(redisStandaloneConfiguration, clientConfigurationBuilder().build());
    }

//    @Bean("redisClusterTemplate")
    public RedisTemplate<String, Object> redisClusterTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisClusterConnectionFactory());
        return redisTemplate;
    }

//    @Bean("redisSentinelTemplate")
    public RedisTemplate<String, Object> redisSentinelTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisSentinelConnectionFactory());
        return redisTemplate;
    }

    //    @Bean("redisGSSentinelTemplate")
    public RedisTemplate<String, Object> redisGSSentinelTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisGSSentinelConnectionFactory());
        return redisTemplate;
    }

    @Bean("redisStandaloneTemplate")
    public RedisTemplate<String, Object> redisStandaloneTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisStandaloneConnectionFactory());

        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        return redisTemplate;
    }

    @Bean("groupServiceRedisTemplate")
    public RedisTemplate<String, Object> groupServiceRedisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(groupServiceJedisStandaloneConnectionFactory());

        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        return redisTemplate;
    }

    private JedisClientConfigurationBuilder clientConfigurationBuilder() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMaxTotal(maxActive);
        poolConfig.setMinIdle(minIdle);
        poolConfig.setMaxWaitMillis(maxWait);

        return JedisClientConfiguration.builder()
                .usePooling()
                .poolConfig(poolConfig)
                .and()
                .connectTimeout(Duration.ofMillis(timeout))
                .readTimeout(Duration.ofMillis(readTimeout))
                .clientName(BusiSpringConfig.class.getName() + ":" + Thread.currentThread().getName());
    }
}
